package com.google.code.jholidays.core;

import java.util.ArrayList;
import java.util.List;

import com.google.code.jholidays.events.IEvent;
import com.google.code.jholidays.events.IFactory;

/**
 * Represents composite factory. It stores internal collection of different
 * {@link IFactory} implementations and implements {@link IFactory} interface
 * itself.
 * <p>
 * When any {@link IFactory} method is called on composite factory it looks
 * through its internal factories collection and redirects method call to items
 * in this collection
 * 
 * @author tillias
 * 
 */
public class CompositeFactory implements IFactory {

    /**
     * Creates new instance of composite factory
     */
    public CompositeFactory() {
	factoryCollection = new ArrayList<IFactory>();
    }

    /**
     * Checks whether composite collection stores given factory
     * 
     * @param factory
     *            Factory to be checked
     * @return True if given factory is stored inside composite factory, false
     *         otherwise
     */
    public boolean contains(IFactory factory) {
	return factoryCollection.contains(factory);
    }

    /**
     * Adds given factory inside composite one. If it already contains given
     * factory does nothing
     * 
     * @param factory
     *            Factory to be added
     * @return True if succeed, false otherwise
     */
    public boolean add(IFactory factory) {
	boolean result = false;

	if (factory != null && !contains(factory)) {
	    factoryCollection.add(factory);
	    result = true;
	}

	return result;
    }

    /**
     * Removes given factory from composite one. If it doesn't contains given
     * factory does nothing
     * 
     * @param factory
     *            Factory to be deleted
     * @return True if succeed, false otherwise
     */
    public IFactory remove(IFactory factory) {
	IFactory result = null;

	if (factoryCollection.remove(factory)) {
	    result = factory;
	}

	return result;
    }

    /**
     * {@inheritDoc}
     * <p>
     * This implementation first of all checks whether any {@link IFactory}
     * implementation that is stored inside internal collection of composite
     * factory can handle given descriptor. If there is one composite factory
     * redirects method call to it. Otherwise method does nothing and returns
     * <tt>null</tt>.
     */
    @Override
    public IEvent createEvent(EventDescriptor descriptor, IEvent parent) {
	IEvent result = null;

	IFactory factory = getFactory(descriptor);

	if (factory != null)
	    result = factory.createEvent(descriptor, parent);

	return result;
    }

    /**
     * {@inheritDoc}
     * <p>
     * This implementation checks whether there exists any {@link IFactory}
     * implementation stored inside internal collection of composite factory
     * that can handle give descriptor. If there exists one redirects method
     * call to this factory. Otherwise does nothing and return null.
     */
    @Override
    public boolean matches(EventDescriptor descriptor) {
	boolean result = false;

	IFactory factory = getFactory(descriptor);

	if (factory != null) // if we've found factory, it already matches
	    result = true;

	return result;
    }

    protected IFactory getFactory(EventDescriptor descriptor) {
	IFactory result = null;

	for (IFactory f : factoryCollection) {
	    if (f.matches(descriptor)) {
		result = f;
		break;
	    }
	}

	return result;
    }

    List<IFactory> factoryCollection;

}
